package pers.zhouyoudianxi.notice2.config;

import org.springframework.stereotype.Service;
import pers.zhouyoudianxi.notice2.bean.Notice;
import pers.zhouyoudianxi.notice2.service.FileService;
import pers.zhouyoudianxi.notice2.service.NoticeService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.scheduling.support.CronTrigger;

import javax.annotation.PostConstruct;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.*;

/**
 * 动态加载cron表达式的定时任务
 * 支持运行时修改cron表达式并立即生效
 */
@Order(Ordered.LOWEST_PRECEDENCE - 1)
@Configuration
@Slf4j
@Service
public class DynamicCronTask {
    @Autowired
    FileService fileService;
    @Autowired
    NoticeService noticeService;

    public static int NEXT_ID = -1; // 用于生成新配置项的ID
    public static List<Notice> NOTICE_LIST;

    @Autowired
    private ThreadPoolTaskScheduler taskScheduler;
    // 存储正在运行的任务Future
    private final Map<Integer, Future<?>> runningTasks = new ConcurrentHashMap<>();

    // 任务执行逻辑注册表：key为任务ID，value为带参数的任务执行器
    private final Map<Integer, TaskExecutor> taskRegistry = new HashMap<>();


    /**
     * 任务执行器接口，支持接收两个字符串参数
     */
    @FunctionalInterface
    public interface TaskExecutor {
        void execute(Notice notice);
    }

    /**
     * 初始化：注册任务并启动所有启用的任务
     */
    @PostConstruct
    public void init() {
        log.info("检查配置文件");
        fileService.initConfig();
        log.info("读取配置文件");
        boolean readConfigFlag = fileService.readConfig();
        if (!readConfigFlag) {
            log.error("检查配置文件并重新运行");
            System.exit(1);
        }
        // 注册所有任务的执行逻辑（实际项目中可按需扩展）
        registerTasks();
        for (int i = 0; i < NOTICE_LIST.size(); i++) {
            Notice notice = NOTICE_LIST.get(i);
            startTask(notice);
        }
        NEXT_ID = NOTICE_LIST.size();
    }

    /**
     * 注册任务执行逻辑
     */
    private void registerTasks() {
        try {
            NOTICE_LIST.stream().forEach((notice) -> {
                taskRegistry.put(notice.getId(), (Notice notice2) -> {
                    noticeService.send(notice2.getTitle(), notice2.getDetail());
                });
            });
        } catch (Exception e) {
            log.info("任务注册失败：{}", e.getMessage());
        }

    }

    /**
     * 启动任务
     */
    public void startTask(Notice config) {
        if (config.getOpen() != 1) {
            log.info("任务[{}]已禁用，不启动", config.getId());
            return;
        }

        // 校验任务是否已注册
        if (!taskRegistry.containsKey(config.getId())) {
            log.error("任务[{}]未注册执行逻辑，无法启动", config.getId());
            return;
        }

        // 停止已有任务（避免重复执行）
        stopTask(config.getId());

        // 创建带参数的任务执行包装器
        Runnable taskWrapper = createTaskWrapper(config);

        // 调度任务
        Future<?> future = taskScheduler.schedule(
                taskWrapper,
                triggerContext -> new CronTrigger(config.getCron()).nextExecutionTime(triggerContext)
        );

        runningTasks.put(config.getId(), future);
        log.info("任务[{}]已启动，cron表达式: {}, 参数1: {}, 参数2: {}",
                config.getId(), config.getCron(),
                config.getTitle(), config.getDetail());
    }

    /**
     * 创建任务包装器，处理参数传递、超时和重试
     */
    private Runnable createTaskWrapper(Notice config) {
        return () -> {
            int retry = 0;
            while (retry <= 3) {
                try {
                    ExecutorService executor = Executors.newSingleThreadExecutor();
                    Future<?> future = executor.submit(() -> {
                        // 从注册表获取任务执行器，并传入动态参数
                        taskRegistry.get(config.getId())
                                .execute(config);
                    });

                    // 执行任务并设置超时
                    future.get(60, TimeUnit.SECONDS);
                    executor.shutdown();
                    break; // 成功执行则退出重试
                } catch (Exception e) {
                    retry++;
                    log.error("任务[{}]执行失败，第{}次重试", config.getId(), retry, e);

                    if (retry > 3) {
                        log.error("任务[{}]达到最大重试次数，执行失败", config.getId());
                        break;
                    }
                    try {
                        Thread.sleep(2000L);
                    } catch (InterruptedException ie) {
                        Thread.currentThread().interrupt();
                        break;
                    }
                }
            }
        };
    }

    /**
     * 停止任务
     */
    public void stopTask(Integer taskId) {
        Future<?> future = runningTasks.get(taskId);
        if (future != null && !future.isCancelled()) {
            future.cancel(true);
            runningTasks.remove(taskId);
            log.info("任务[{}]已停止", taskId);
        }
    }

    /**
     * 更新任务配置（动态修改cron和参数）
     */
    public void updateTaskConfig() {
        log.info("检查配置文件是否有更新中……");
        log.info("开始更新任务");
        fileService.writeConfig();
        try {
            log.info("取消全部已注册任务");
            NOTICE_LIST.stream().forEach((notice) -> {
                stopTask(notice.getId());
            });
            log.info("重新注册所有任务");
            registerTasks();
            log.info("启动所有任务");
            NOTICE_LIST.stream().forEach((notice) -> {
                startTask(notice);
            });
            NEXT_ID = NOTICE_LIST.size();
        } catch (Exception e) {
            log.info("任务取消失败：{}", e.getMessage());
        }
        log.info("结束更新任务");
    }


    /**
     * @param str
     * @return
     */
    public static String removeControlChars(String str) {
        if (str == null) {
            return null;
        }
        // 正则表达式匹配所有空白控制字符：\t\n\n\n\r\f\v
        return str.replaceAll("[\n\r\t]", "");
    }

}
